home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / ici / ici.cpi / skt.c < prev    next >
C/C++ Source or Header  |  1994-10-27  |  27KB  |  1,175 lines

  1. /*
  2.  * skt.c - ICI sockets interface
  3.  *
  4.  * This is a set of extra intrinsic functions to provide ICI programs
  5.  * with access to the BSD sockets interface to the IP protocol (there is
  6.  * currently no support for other protocol families but it is easily
  7.  * provided.)
  8.  *
  9.  * The ICI interface does not follow the BSD C interface but adopts
  10.  * practices suitable for the ICI environment.
  11.  */
  12.  
  13. #include "fwd.h"
  14. #ifndef    NOSKT
  15. #include <string.h>
  16. #include <sys/param.h>
  17. #undef isset /* sys/param.h defines set macros that conflict with ICI's */
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <netdb.h>
  22. #include <arpa/inet.h>
  23. #include <sys/time.h>
  24. #include <pwd.h>
  25. #if __hpux
  26. #include <unistd.h>
  27. #endif
  28.  
  29. #include "buf.h"
  30. #include "exec.h"
  31. #include "op.h"
  32. #include "fwd.h"
  33. #include "func.h"
  34. #include "int.h"
  35. #include "set.h"
  36. #include "struct.h"
  37. #include "str.h"
  38. #include "skt.h"
  39.  
  40. string_t *string_read;
  41. string_t *string_write;
  42. string_t *string_except;
  43. string_t *string_msg;
  44. string_t *string_addr;
  45.  
  46. #if defined(sun) && __STDC__
  47. int close(int);
  48. int socket(int, int, int);
  49. int listen(int, int);
  50. int accept(int, struct sockaddr *, int *);
  51. int connect(int, struct sockaddr *, int);
  52. int bind(int, struct sockaddr *, int);
  53. int getdtablesize(void);
  54. int sendto(int, char *, int, int, struct sockaddr *, int);
  55. int send(int, char *, int, int);
  56. int recvfrom(int, char *, int, int, struct sockaddr *, int *);
  57. int recv(int, char *, int, int);
  58. int getsockopt(int, int, int, char *, int *);
  59. int setsockopt(int, int, int, char *, int);
  60. int getdomainname(char *, int);
  61. int gethostname(char *, int);
  62. int getuid(void);
  63. int getpeername(int, struct sockaddr *, int *);
  64. int getsockname(int, struct sockaddr *, int *);
  65. #endif
  66.  
  67. /*
  68.  * Definitions to make a new type, socket, for representing network connections
  69.  */
  70.  
  71. STATIC long
  72. mark_socket(o)
  73. object_t    *o;
  74. {
  75.     o->o_flags |= O_MARK;
  76.     return sizeof (skt_t);
  77. }
  78.  
  79. STATIC long
  80. hash_socket(s)
  81. skt_t    *s;
  82. {
  83.     return (long)s->s_skt * 7;
  84. }
  85.  
  86. STATIC int
  87. cmp_socket(s1, s2)
  88. skt_t    *s1;
  89. skt_t    *s2;
  90. {
  91.     return s1->s_skt != s2->s_skt;
  92. }
  93.  
  94. type_t    socket_type =
  95. {
  96.     mark_socket,
  97.     free_simple,
  98.     hash_socket,
  99.     cmp_socket,
  100.     copy_simple,
  101.     assign_simple,
  102.     fetch_simple,
  103.     "socket"
  104. };
  105.  
  106. skt_t *
  107. new_socket(fd)
  108. int fd;
  109. {
  110.     skt_t    *s;
  111.     if ((s = talloc(skt_t)) != NULL)
  112.     {
  113.     objof(s)->o_type = &socket_type;
  114.     objof(s)->o_tcode = TC_OTHER;
  115.     objof(s)->o_flags = 0;
  116.     objof(s)->o_nrefs = 1;
  117.     s->s_skt = fd;
  118.     rego(s);
  119.     }
  120.     return sktof(atom(objof(s), 1));
  121. }
  122.  
  123. static int need_strings = 1;
  124. static int
  125. define_strings()
  126. {
  127.     if ((string_read = new_cname("read")) == NULL)
  128.         return 1;
  129.     if ((string_write = new_cname("write")) == NULL)
  130.         return 1;
  131.     if ((string_except = new_cname("except")) == NULL)
  132.         return 1;
  133.     if ((string_msg = new_cname("msg")) == NULL)
  134.         return 1;
  135.     if ((string_addr = new_cname("addr")) == NULL)
  136.         return 1;
  137.     return need_strings = 0;
  138. }
  139.  
  140. /*
  141.  * Parse an IP address in the format "service[@host]" where service is a
  142.  * port number of service name (in the form "name[/proto]" where name is
  143.  * the name of the service and, the optional, proto is either "tcp" or
  144.  * "udp"). The host part is optional and if not specified defaults to
  145.  * the defhost parameter. The host may be specified as an IP address
  146.  * in dotted decimal notation or as a hostname. Three special values
  147.  * are recognsied, "." stands for the local host, "?" stands for any
  148.  * host and "*" means broadcast. The address may be NULL to just
  149.  * initialise the socket address to defhost port 0.
  150.  *
  151.  * The sockaddr structure is filled in and 0 returned if all is okay.
  152.  * When a error occurs the error string is set and 1 is returned.
  153.  */
  154. static struct sockaddr_in *
  155. parseaddr(raddr, defhost, saddr)
  156. char *raddr;
  157. long defhost;
  158. struct sockaddr_in *saddr;
  159. {
  160.     char addr[1024];
  161.     char *host;
  162.     short port;
  163.     saddr->sin_family = PF_INET;
  164.     saddr->sin_addr.s_addr = defhost;
  165.     saddr->sin_port = 0;
  166.     if (raddr == NULL)
  167.         return saddr;
  168.     strcpy(addr, raddr);
  169.     if ((host = strchr(addr, '@')) != NULL)
  170.     {
  171.         struct hostent *hostent;
  172.         long hostaddr;
  173.         *host++ = 0;
  174.         if (!strcmp(host, "."))
  175.             hostaddr = INADDR_LOOPBACK;
  176.         else if (!strcmp(host, "?"))
  177.             hostaddr = INADDR_ANY;
  178.         else if (!strcmp(host, "*"))
  179.             hostaddr = INADDR_BROADCAST;
  180.         else if ((hostent = gethostbyname(host)) != NULL)
  181.             memcpy(&hostaddr, hostent->h_addr, sizeof hostaddr);
  182.         else
  183.         {
  184.             error = "unknown host";
  185.             return NULL;
  186.         }
  187.         saddr->sin_addr.s_addr = hostaddr;
  188.     }
  189.     if (sscanf(addr, "%hu", &port) != 1)
  190.     {
  191.     char *proto;
  192.     struct servent *servent;
  193.         if ((proto = strchr(addr, '/')) != NULL)
  194.             *proto++ = 0;
  195.         if ((servent = getservbyname(addr, proto)) == NULL)
  196.         {
  197.             error = "unknown service";
  198.             return NULL;
  199.         }
  200.         port = ntohs(servent->s_port);
  201.     }
  202.     saddr->sin_port = htons(port);
  203.     return saddr;
  204. }
  205.  
  206. /*
  207.  * Turn a port number and IP address into a nice looking string ;-)
  208.  */
  209. static char *
  210. unparse_addr(addr)
  211. struct sockaddr_in *addr;
  212. {
  213.     static char buf[256];
  214.     struct servent *serv;
  215.     struct hostent *host;
  216.     if ((serv = getservbyport(addr->sin_port, NULL)) != NULL)
  217.     strcpy(buf, serv->s_name);
  218.     else
  219.     sprintf(buf, "%d", addr->sin_port);
  220.     strcat(buf, "@");
  221.     if ((host = gethostbyaddr((char *)addr->sin_addr.s_addr, sizeof addr->sin_addr, AF_INET)) == NULL)
  222.     strcat(buf, inet_ntoa(addr->sin_addr));
  223.     else
  224.     strcat(buf, host->h_name);
  225.     return buf;
  226. }
  227.  
  228. /*
  229.  * Error return utility. Formats the exception string with the
  230.  * the message followed by the system error message and returns
  231.  * 1 for use in error returns.
  232.  */
  233. static int
  234. serr(msg)
  235. char *msg;
  236. {
  237.     sprintf(buf, "%s: %s", msg, syserr());
  238.     error = buf;
  239.     return 1;
  240. }
  241.  
  242. /*
  243.  * Create a socket with a certain protocol (currently TCP or UDP)
  244.  * and return its descriptor. Raises exception if the protocol
  245.  * is unknown or the socket cannot be created.
  246.  *
  247.  * ICI usage,
  248.  *
  249.  *    skt = socket(proto);
  250.  *
  251.  * Where proto is a string ("tcp" or "udp") and the result is the socket.
  252.  */
  253. STATIC int
  254. f_socket()
  255. {
  256.     skt_t *skt;
  257.     char *proto;
  258.     int type;
  259.     int fd;
  260.     if (typecheck("s", &proto))
  261.         return 1;
  262.     if (!strcmp(proto, "tcp"))
  263.         type = SOCK_STREAM;
  264.     else if (!strcmp(proto, "udp"))
  265.         type = SOCK_DGRAM;
  266.     else
  267.     {
  268.         error = "unsupported protocol";
  269.         return 1;
  270.     }
  271.     if ((fd = socket(PF_INET, type, 0)) == -1)
  272.         return serr("socket");
  273.     if ((skt = new_socket(fd)) == NULL)
  274.     {
  275.     close(fd);
  276.     return 1;
  277.     }
  278.     return loose_ret(objof(skt));
  279. }
  280.  
  281. /*
  282.  * Tell the system to listen for connections on a socket. Raises
  283.  * the appropriate system exception if it fails.
  284.  *
  285.  * ICI usage,
  286.  *
  287.  *    skt = listen(skt);
  288.  *
  289.  * Where skt is the socket descriptor as returned by socket(). The
  290.  * result of listen is its parameter (to allow "functional" programming.)
  291.  *    
  292.  */
  293. STATIC int
  294. f_listen()
  295. {
  296.     skt_t *skt;
  297.     if (typecheck("o", &skt))
  298.         return 1;
  299.     if (!isskt(objof(skt)))
  300.     return argerror(0);
  301.     if (listen(skt->s_skt, 5) == -1)
  302.         return serr("listen");
  303.     return loose_ret(objof(skt));
  304. }
  305.  
  306. /*
  307.  * Accept a connection on a socket. Returns the descriptor for the
  308.  * new socket connection or raises an exception.
  309.  *
  310.  * ICI usage,
  311.  *
  312.  *    new_skt = accept(skt);
  313.  *
  314.  * Where skt is a socket descriptor of a TCP socket that has been
  315.  * marked to accept connections (i.e., been passed to listen()).
  316.  * The result is the socket descriptor of the new connection.
  317.  */
  318. STATIC int
  319. f_accept()
  320. {
  321.     skt_t    *skt;
  322.     skt_t    *new;
  323.     int        fd;
  324.     
  325.     if (typecheck("o", &skt))
  326.         return 1;
  327.     if (!isskt(objof(skt)))
  328.     return argerror(0);
  329.     if ((fd = accept(skt->s_skt, NULL, NULL)) == -1)
  330.         return serr("accept");
  331.     if ((new = new_socket(fd)) != NULL)
  332.     got(new);
  333.     return obj_ret(objof(new));
  334. }
  335.  
  336. /*
  337.  * Connect a socket to an address. Raises an exception if it fails
  338.  * for some reason or returns the socket passed as the first
  339.  * parameter which is now connected to the address specified as
  340.  * the second parameter.
  341.  *
  342.  * ICI usage,
  343.  *
  344.  *    skt = connect(skt, address);
  345.  *
  346.  * Skt is a socket desciptor and address is a network address as
  347.  * accepted by parseaddr().
  348.  *
  349.  */
  350. STATIC int
  351. f_connect()
  352. {
  353.     skt_t *skt;
  354.     char *addr;
  355.     struct sockaddr_in sockaddr;
  356.     if (typecheck("os", &skt, &addr))
  357.         return 1;
  358.     if (!isskt(objof(skt)))
  359.     return argerror(0);
  360.     if (parseaddr(addr, INADDR_LOOPBACK, &sockaddr) == NULL)
  361.         return 1;
  362.     if (connect(skt->s_skt, (struct sockaddr *)&sockaddr, sizeof sockaddr) == -1)
  363.         return serr("connect");
  364.     return loose_ret(objof(skt));
  365. }
  366.  
  367. /*
  368.  * Bind an address to a socket. Returns socket descriptor or raises
  369.  * an exception. Default host address is INADDR_ANY which is mostly
  370.  * used with TCP sockets for servers (i.e. a server can use the
  371.  * code "bind(socket("tcp"), port)" to create their sockets.)
  372.  */
  373. STATIC int
  374. f_bind()
  375. {
  376.     skt_t *skt;
  377.     char *addr;
  378.     struct sockaddr_in sockaddr;
  379.     if (typecheck("os", &skt, &addr))
  380.         return 1;
  381.     if (!isskt(objof(skt)))
  382.     return argerror(0);
  383.     if (parseaddr(addr, INADDR_ANY, &sockaddr) == NULL)
  384.         return 1;
  385.     if (bind(skt->s_skt, (struct sockaddr *)&sockaddr, sizeof sockaddr) == -1)
  386.         return serr("bind");
  387.     return loose_ret(objof(skt));
  388. }
  389.  
  390. #if __hpux
  391. /*
  392.  * Fake getdtablesize(2) call for HPUS.
  393.  */
  394. static int
  395. getdtablesize()
  396. {
  397.     return (int)sysconf(_SC_OPEN_MAX);
  398. }
  399. #endif
  400.  
  401. /*
  402.  * Check for ready sockets with optional timeout. This returns a
  403.  * structure of three sets of descriptors. The parameters to
  404.  * this function are complex. It takes two types of parameters,
  405.  * an integer timeout value (in milliseconds) or up to to three
  406.  * sets of socket descriptors (at least one set must be passed.)
  407.  * The first set is taken to be the sockets to check for reading,
  408.  * the second set is checked for writing and the third set is
  409.  * checked for "urgent" status. The write and urgent sets are
  410.  * optional. Any set may be specified as NULL. This is used to
  411.  * specify, say, just a write set when there is no read set.
  412.  * The read set must be specified (becauses the others are
  413.  * optional) but there are no members.
  414.  */
  415. STATIC int
  416. f_select()
  417. {
  418.     int i;
  419.     int n;
  420.     int dtabsize;
  421.     long timeout = -1;
  422.     struct fd_set fds[3];
  423.     struct fd_set *rfds = NULL, *wfds = NULL, *efds = NULL;
  424.     struct timeval timeval, *tv;
  425.     struct_t *result;
  426.     set_t *set;
  427.  
  428.     if (need_strings && define_strings())
  429.         return 1;
  430.     if (NARGS() == 0)
  431.     {
  432.         error = "incorrect number of arguments for select()";
  433.         return 1;
  434.     }
  435.     for (i = 0; i < NARGS(); ++i)
  436.     {
  437.         if (isint(ARG(i)))
  438.         {
  439.             if (timeout != -1)
  440.             {
  441.                 error = "more than one timeout parameter";
  442.                 return 1;
  443.             }
  444.             timeout = intof(ARG(i))->i_value;
  445.             if (timeout < 0)
  446.             {
  447.                 error = "bad timeout";
  448.                 return 1;
  449.             }
  450.         }
  451.         else if (isset(ARG(i)) || isnull(ARG(i)))
  452.         {
  453.             int whichset = -1; /* Can be 0, 1 or 2 */
  454.             int j;
  455.             slot_t *sl;
  456.             if (++whichset > 2)
  457.             {
  458.                 error = "too many set parameters to select()";
  459.                 return 1;
  460.             }
  461.             if (isnull(ARG(i)))
  462.             {
  463.                 switch (whichset)
  464.                 {
  465.                 case 0:
  466.                     rfds = NULL;
  467.                     break;
  468.                 case 1:
  469.                     wfds = NULL;
  470.                     break;
  471.                 case 2:
  472.                     efds = NULL;
  473.                     break;
  474.                 }
  475.             }
  476.             else
  477.             {
  478.                 struct fd_set *fs = 0;
  479.                 switch (whichset)
  480.                 {
  481.                 case 0:
  482.                     fs = rfds = &fds[0];
  483.                     break;
  484.                 case 1:
  485.                     fs = wfds = &fds[1];
  486.                     break;
  487.                 case 2:
  488.                     fs = efds = &fds[2];
  489.                     break;
  490.                 }
  491.                 FD_ZERO(fs);
  492.                 set = setof(ARG(i));
  493.                 for (j = 0; j < set->s_nslots; ++j)
  494.                 {
  495.                     int k;
  496.                     if ((sl = (slot_t *)&set->s_slots[j])->sl_key == NULL)
  497.                         continue;
  498.                     if (!isskt(sl->sl_key))
  499.                         continue;
  500.                     k = sktof(sl->sl_key)->s_skt;
  501.                     FD_SET(k, fs);
  502.                 }
  503.             }
  504.         }
  505.         else
  506.         {
  507.             sprintf(buf, "select() passed a %s", ARG(i)->o_type->t_name);
  508.             error = buf;
  509.             return 1;
  510.         }
  511.     }
  512.     if (rfds == NULL && wfds == NULL && efds == NULL)
  513.     {
  514.         error = "no set parameters to select";
  515.         return 1;
  516.     }
  517.     if (timeout == -1)
  518.         tv = NULL;
  519.     else
  520.     {
  521.         tv = &timeval;
  522.         tv->tv_sec = timeout / 1000;
  523.         tv->tv_usec = (timeout % 1000) * 1000;
  524.     }
  525.     dtabsize = getdtablesize();
  526.     if ((n = select(dtabsize, rfds, wfds, efds, tv)) < 0)
  527.     {
  528.         error = syserr();
  529.         return 1;
  530.     }
  531.     if (n == 0)
  532.     {
  533.         error = "timeout";
  534.         return 1;
  535.     }
  536.     if ((result = new_struct()) == NULL)
  537.         return 1;
  538.     if ((set = new_set()) == NULL)
  539.     goto fail;
  540.     for (i = 0; n > 0 && i < dtabsize; ++i)
  541.     {
  542.     if (FD_ISSET(i, rfds))
  543.     {
  544.         skt_t *ii = new_socket(i);
  545.         if (ii == NULL)
  546.         {
  547.         loose(objof(set));
  548.         goto fail;
  549.         }
  550.         loose(objof(ii));
  551.         if (assign(set, ii, objof(o_one)))
  552.         {
  553.         loose(objof(set));
  554.         goto fail;
  555.         }
  556.         --n;
  557.     }
  558.     }
  559.     loose(objof(set));
  560.     if (assign(result, string_read, set))
  561.     goto fail;
  562.     if ((set = new_set()) == NULL)
  563.     goto fail;
  564.     for (i = 0; n > 0 && i < dtabsize; ++i)
  565.     {
  566.     if (FD_ISSET(i, wfds))
  567.     {
  568.         skt_t *ii = new_socket(i);
  569.         if (ii == NULL)
  570.         {
  571.         loose(objof(set));
  572.         goto fail;
  573.         }
  574.         loose(objof(ii));
  575.         if (assign(set, ii, objof(o_one)))
  576.         {
  577.         loose(objof(set));
  578.         goto fail;
  579.         }
  580.         --n;
  581.     }
  582.     }
  583.     loose(objof(set));
  584.     if (assign(result, string_write, set))
  585.     goto fail;
  586.     if ((set = new_set()) == NULL)
  587.     goto fail;
  588.     for (i = 0; n > 0 && i < dtabsize; ++i)
  589.     {
  590.     if (FD_ISSET(i, efds))
  591.     {
  592.         skt_t *ii = new_socket(i);
  593.         if (ii == NULL)
  594.         {
  595.         loose(objof(set));
  596.         goto fail;
  597.         }
  598.         if (assign(set, ii, objof(o_one)))
  599.         {
  600.         loose(objof(set));
  601.         goto fail;
  602.         }
  603.         --n;
  604.     }
  605.     }
  606.     loose(objof(set));
  607.     if (assign(result, string_except, set))
  608.     goto fail;
  609.     return loose_ret(objof(result));
  610.  
  611. fail:
  612.     loose(objof(result));
  613.     return 1;
  614. }
  615.  
  616. /*
  617.  * Send a message to a specific address.
  618.  *
  619.  * Usage
  620.  *
  621.  *      sendto(skt, msg, address)
  622.  *
  623.  */
  624. STATIC int
  625. f_sendto()
  626. {
  627.     char *addr, *msg;
  628.     int len, n;
  629.     skt_t *skt;
  630.     struct sockaddr_in sockaddr;
  631.     if (typecheck("oss", &skt, &msg, &addr))
  632.         return 1;
  633.     if (!isskt(objof(skt)))
  634.     return argerror(0);
  635.     len = strlen(msg);
  636.     if (parseaddr(addr, INADDR_LOOPBACK, &sockaddr) == NULL)
  637.         return 1;
  638.     if ((n = sendto(skt->s_skt, msg, len, 0, (struct sockaddr *)&sockaddr, sizeof sockaddr)) < 0)
  639.         return serr("sendto");
  640.     if (n != len)
  641.     {
  642.         error = "short write";
  643.         return 1;
  644.     }
  645.     return loose_ret(objof(&o_null));
  646. }
  647.  
  648. #if 0
  649. /*
  650.  * Turn a textual send option into the correct bits
  651.  */
  652. static int
  653. flagval(flag)
  654. char *flag;
  655. {
  656.     if (!strcmp(flag, "oob"))
  657.     return MSG_OOB;
  658.     if (!strcmp(flag, "peek"))
  659.     return MSG_PEEK;
  660.     if (!strcmp(flag, "dontroute"))
  661.     return MSG_DONTROUTE;
  662.     return -1;
  663. }
  664. #endif
  665.  
  666. /*
  667.  * Receive a message and get the source address. This returns a structure
  668.  * (at the ICI level) containing the data, in result.msg, and the address
  669.  * in result.addr.
  670.  */
  671. STATIC int
  672. f_recvfrom()
  673. {
  674.     skt_t *skt;
  675.     int len;
  676.     int nb;
  677.     char *msg;
  678.     struct sockaddr_in addr;
  679.     int addrsz = sizeof addr;
  680.     struct_t *result;
  681.     string_t *s;
  682.  
  683.     if (need_strings && define_strings())
  684.         return 1;
  685.     if (typecheck("oi", &skt, &len))
  686.     return 1;
  687.     if (!isskt(objof(skt)))
  688.     return argerror(0);
  689.     if ((msg = zalloc(len+1)) == NULL)
  690.     return 1;
  691.     if ((nb = recvfrom(skt->s_skt, msg, len, 0, (struct sockaddr *)&addr, &addrsz)) == -1)
  692.     {
  693.         zfree(msg);
  694.     return serr("recv");
  695.     }
  696.     if (nb == 0)
  697.     {
  698.     zfree(msg);
  699.     return loose_ret(objof(&o_null));
  700.     }
  701.     msg[nb] = 0;
  702.     if ((result = new_struct()) == NULL)
  703.     {
  704.         zfree(msg);
  705.         return 1;
  706.     }
  707.     loose(result);
  708.     if ((s = new_cname(msg)) == NULL)
  709.     {
  710.         zfree(msg);
  711.         return 1;
  712.     }
  713.     zfree(msg);
  714.     if (assign(result, string_msg, s))
  715.         return 1;
  716.     if ((s = new_cname(unparse_addr(&addr))) == NULL)
  717.         return 1;
  718.     if (assign(result, string_addr, s))
  719.         return 1;
  720.     return obj_ret(objof(result));
  721. }
  722.  
  723. /*
  724.  * Send a message on a socket.
  725.  */
  726. STATIC int
  727. f_send()
  728. {
  729.     skt_t *skt;
  730.     int len;
  731.     char *msg;
  732.     if (typecheck("os", &skt, &msg))
  733.     return 1;
  734.     if (!isskt(objof(skt)))
  735.     return argerror(0);
  736.     len = strlen(msg);
  737.     if (send(skt->s_skt, msg, len, 0) != len)
  738.     {
  739.     error = "short write";
  740.     return 1;
  741.     }
  742.     return loose_ret(objof(&o_null));
  743. }
  744.  
  745. /*
  746.  * Receive a message.
  747.  */
  748. STATIC int
  749. f_recv()
  750. {
  751.     skt_t *skt;
  752.     int len;
  753.     int nb;
  754.     int rc;
  755.     char *msg;
  756.     if (typecheck("oi", &skt, &len))
  757.     return 1;
  758.     if (!isskt(objof(skt)))
  759.     return argerror(0);
  760.     if ((msg = zalloc(len+1)) == NULL)
  761.     return 1;
  762.     if ((nb = recv(skt->s_skt, msg, len, 0)) == -1)
  763.     {
  764.         free(msg);
  765.     return serr("recv");
  766.     }
  767.     if (nb == 0)
  768.     {
  769.     zfree(msg);
  770.     return loose_ret(objof(&o_null));
  771.     }
  772.     msg[nb] = 0;
  773.     rc = str_ret(msg);
  774.     zfree(msg);
  775.     return rc;
  776. }
  777.  
  778. /*
  779.  * Turn a textual socket option name to the actual number.
  780.  */
  781. static int
  782. sockopt(opt)
  783. char *opt;
  784. {
  785.     long o = -1;
  786.     int i;
  787.     static struct
  788.     {
  789.         char *name;
  790.         int  value;
  791.     }
  792.     opts[] =
  793.     {
  794.         {"debug",    SO_DEBUG},
  795.         {"reuseaddr",    SO_REUSEADDR},
  796.         {"keepalive",    SO_KEEPALIVE},
  797.         {"dontroute",    SO_DONTROUTE},
  798.     {"useloopback", SO_USELOOPBACK},
  799.         {"linger",    SO_LINGER},
  800.         {"broadcast",    SO_BROADCAST},
  801.         {"oobinline",    SO_OOBINLINE},
  802.         {"sndbuf",    SO_SNDBUF},
  803.         {"rcvbuf",    SO_RCVBUF},
  804.         {"type",    SO_TYPE},
  805.         {"error",    SO_ERROR}
  806.     };
  807.     for (i = 0; o == -1 && i < sizeof opts/sizeof opts[0]; ++i)
  808.         if (!strcmp(opt, opts[i].name))
  809.             o = opts[i].value;
  810.     return o;
  811. }
  812.  
  813. /*
  814.  * Get socket options.
  815.  *
  816.  * All option values get returned as integers. The only special processing
  817.  * is of the "linger" option. This gets returned as the lingering time if
  818.  * it is set or -1 if lingering is not enabled.
  819.  */
  820. STATIC int
  821. f_getsockopt()
  822. {
  823.     skt_t *skt;
  824.     char *opt;
  825.     int o;
  826.     char *optval;
  827.     int optlen;
  828.     struct linger linger;
  829.     int intvar;
  830.     
  831.     optval = (char *)&intvar;
  832.     optlen = sizeof intvar;
  833.     if (typecheck("os", &skt, &opt))
  834.         return 1;
  835.     if (!isskt(objof(skt)))
  836.     return argerror(0);
  837.     switch (o = sockopt(opt))
  838.     {
  839.     case SO_DEBUG:
  840.     case SO_REUSEADDR:
  841.     case SO_KEEPALIVE:
  842.     case SO_DONTROUTE:
  843.     case SO_BROADCAST:
  844.     case SO_TYPE:
  845.     case SO_OOBINLINE:
  846.     case SO_SNDBUF:
  847.     case SO_RCVBUF:
  848.     case SO_ERROR:
  849.     break;
  850.     case SO_LINGER:
  851.     optval = (char *)&linger;
  852.     optlen = sizeof linger;
  853.     break;
  854.     default:
  855.         sprintf(buf, "bad socket option \"%s\"", opt);
  856.         error = buf;
  857.         return 1;    
  858.     }
  859.     if (getsockopt(skt->s_skt, SOL_SOCKET, o, optval, &optlen) == -1)
  860.     return serr("getsockopt");
  861.     if (o == SO_LINGER)
  862.     intvar = linger.l_onoff ? linger.l_linger : -1;
  863.     else
  864.     {
  865.     switch (o)
  866.     {
  867.     case SO_TYPE:
  868.     case SO_SNDBUF:
  869.     case SO_RCVBUF:
  870.     case SO_ERROR:
  871.         break;
  872.     default:
  873.         intvar = !!intvar;
  874.     }
  875.     }
  876.     return int_ret(intvar);
  877. }
  878.  
  879. /*
  880.  * Set socket options.
  881.  *
  882.  * All socket options are integers. Again linger is a special case. The
  883.  * option value is the linger time, if zero or negative lingering is
  884.  * turned off.
  885.  */
  886. STATIC int
  887. f_setsockopt()
  888. {
  889.     skt_t *skt;
  890.     char *opt;
  891.     int o;
  892.     char *optval;
  893.     int optlen;
  894.     int intvar;
  895.     struct linger linger;
  896.     optval = (char *)&intvar;
  897.     optlen = sizeof intvar;
  898.     if (typecheck("osi", &skt, &opt, &intvar))
  899.         return 1;
  900.     if (!isskt(objof(skt)))
  901.     return argerror(0);
  902.     switch (o = sockopt(opt))
  903.     {
  904.     case SO_DEBUG:
  905.     case SO_REUSEADDR:
  906.     case SO_KEEPALIVE:
  907.     case SO_DONTROUTE:
  908.     case SO_BROADCAST:
  909.     case SO_TYPE:
  910.     case SO_OOBINLINE:
  911.     case SO_SNDBUF:
  912.     case SO_RCVBUF:
  913.     case SO_ERROR:
  914.     break;
  915.     case SO_LINGER:
  916.     linger.l_onoff = intvar > 0;
  917.     linger.l_linger = intvar;
  918.     optval = (char *)&linger;
  919.     optlen = sizeof linger;
  920.     break;
  921.     default:
  922.         sprintf(buf, "bad socket option \"%s\"", opt);
  923.         error = buf;
  924.         return 1;
  925.     }
  926.     if (setsockopt(skt->s_skt, SOL_SOCKET, o, optval, optlen) == -1)
  927.     return serr("setsockopt");
  928.     return loose_ret(objof(&o_null));
  929. }
  930.  
  931. /*
  932.  * Get the domain name for the host.
  933.  */
  934. STATIC int
  935. f_domainname()
  936. {
  937.     static string_t *domainname = NULL;
  938.     if (domainname == NULL)
  939.     {
  940.         char buf[1024];
  941.         if (getdomainname(buf, sizeof buf) == -1)
  942.             return serr("getdomainname");
  943.         if ((domainname = new_cname(buf)) == NULL)
  944.             return 1;
  945.         got(domainname);
  946.     }
  947.     return loose_ret((object_t *)stringof(domainname));
  948. }
  949.  
  950. /*
  951.  * Get the host name as a string.
  952.  */
  953. STATIC int
  954. f_hostname()
  955. {
  956.     static string_t *hostname = NULL;
  957.     if (hostname == NULL)
  958.     {
  959.         char buf[MAXHOSTNAMELEN];
  960.         if (gethostname(buf, sizeof buf) == -1)
  961.             return serr("gethostname");
  962.         if ((hostname = new_cname(buf)) == NULL)
  963.             return 1;
  964.         got(hostname);
  965.     }
  966.     return loose_ret((object_t *)stringof(hostname));
  967. }
  968.  
  969. /*
  970.  * Return the name of the current user or the user with the given uid.
  971.  */
  972. STATIC int
  973. f_username()
  974. {
  975.     char *getenv();
  976.     struct passwd *pwent;
  977.     long uid = getuid();
  978.     char *s;
  979.  
  980.     if (NARGS() > 0)
  981.     {
  982.         if (typecheck("i", &uid))
  983.             return 1;
  984.     }
  985.     if ((pwent = getpwuid(uid)) == NULL)
  986.     {
  987.     sprintf(buf, "can't find name for uid %ld", uid);
  988.     error = buf;
  989.     return 1;
  990.     }
  991.     s = pwent->pw_name;
  992.     return loose_ret((object_t *)new_cname(s));
  993. }
  994.  
  995. /*
  996.  * Get the address of the connected socket's client.
  997.  */
  998. STATIC int
  999. f_getpeername()
  1000. {
  1001.     struct sockaddr_in addr;
  1002.     int len = sizeof addr;
  1003.     skt_t *skt;
  1004.     if (typecheck("o", &skt))
  1005.     return 1;
  1006.     if (!isskt(objof(skt)))
  1007.     return argerror(0);
  1008.     if (getpeername(skt->s_skt, (struct sockaddr *)&addr, &len) == -1)
  1009.     return serr("getpeername");
  1010.     return str_ret(unparse_addr(&addr));
  1011. }
  1012.  
  1013. /*
  1014.  * Get a socket's address.
  1015.  */
  1016. STATIC int
  1017. f_getsockname()
  1018. {
  1019.     struct sockaddr_in addr;
  1020.     int len = sizeof addr;
  1021.     skt_t *skt;
  1022.     if (typecheck("o", &skt))
  1023.     return 1;
  1024.     if (!isskt(objof(skt)))
  1025.     return argerror(0);
  1026.     if (getsockname(skt->s_skt, (struct sockaddr *)&addr, &len) == -1)
  1027.     return serr("getsockname");
  1028.     return str_ret(unparse_addr(&addr));
  1029. }
  1030.  
  1031. /*
  1032.  * Get the port number bound to a socket.
  1033.  */
  1034. STATIC int
  1035. f_getportno()
  1036. {
  1037.     struct sockaddr_in addr;
  1038.     int len = sizeof addr;
  1039.     skt_t *skt;
  1040.     if (typecheck("o", &skt))
  1041.     return 1;
  1042.     if (!isskt(objof(skt)))
  1043.     return argerror(0);
  1044.     if (getsockname(skt->s_skt, (struct sockaddr *)&addr, &len) == -1)
  1045.     return serr("getsockname");
  1046.     return int_ret(addr.sin_port);
  1047. }
  1048.  
  1049. /*
  1050.  * Return the IP address for the specified host. The address is returned
  1051.  * as a string containing the dotted decimal form of the host's address.
  1052.  * If the host's address cannot be resolved an error, "no such host"
  1053.  * is raised.
  1054.  */
  1055. STATIC int
  1056. f_gethostbyname()
  1057. {
  1058.     char        *name;
  1059.     struct hostent    *hostent;
  1060.     struct in_addr    addr;
  1061.     if (typecheck("s", &name))
  1062.     return 1;
  1063.     if ((hostent = gethostbyname(name)) == NULL)
  1064.     {
  1065.     error = "no such host";
  1066.     return 1;
  1067.     }
  1068.     memcpy(&addr, *hostent->h_addr_list, sizeof addr);
  1069.     return str_ret(inet_ntoa(addr));
  1070. }
  1071.  
  1072. /*
  1073.  * Return the name of a host given an IP address. The IP address is
  1074.  * specified as either a string containing an address in dotted
  1075.  * decimal or an integer (remember ICI ints are at least 32 bits.)
  1076.  * The name is returned as a string. If the name cannot be resolved
  1077.  * an exception, "unknown host", is raised.
  1078.  */
  1079. STATIC int
  1080. f_gethostbyaddr()
  1081. {
  1082.     long intaddr;
  1083.     char *straddr = NULL;
  1084.     if (typecheck("s", &straddr))
  1085.     {
  1086.         straddr = 0;
  1087.         if (typecheck("i", &intaddr))
  1088.             return 1;
  1089.     }
  1090.     return 1;
  1091. }
  1092.  
  1093. /* 
  1094.  * f_sktno - return the OS socket descriptor (file descriptor) for a socket
  1095.  */
  1096. STATIC int
  1097. f_sktno()
  1098. {
  1099.     skt_t    *skt;
  1100.  
  1101.     if (typecheck("o", &skt))
  1102.     return 1;
  1103.     if (!isskt(objof(skt)))
  1104.     return argerror(0);
  1105.     return int_ret(skt->s_skt);
  1106. }
  1107.  
  1108. /*
  1109.  * f_sktopen - turn a socket descriptor into a file
  1110.  */
  1111. STATIC int
  1112. f_sktopen()
  1113. {
  1114.     skt_t    *skt;
  1115.     char    *mode;
  1116.     FILE    *stream;
  1117.     file_t    *f;
  1118.  
  1119.     if (typecheck("os", &skt, &mode))
  1120.     {
  1121.     if (typecheck("o", &skt))
  1122.         return 1;
  1123.     mode = "r";
  1124.     }
  1125.     if (!isskt(objof(skt)))
  1126.     return argerror(0);
  1127.     if ((stream = fdopen(skt->s_skt, mode)) == NULL)
  1128.     {
  1129.     error = "can't fdopen";
  1130.     return 1;
  1131.     }
  1132.     if ((f = new_file((char *)stream, &stdio_ftype, NULL)) == NULL)
  1133.     {
  1134.     fclose(stream);
  1135.     return 1;
  1136.     }
  1137.     return obj_ret(objof(f));
  1138. }
  1139.  
  1140. /*
  1141.  * This is the configuration table that defines our functions to
  1142.  * the interpreter. The CF_OBJ macro comes from func.h and defines
  1143.  * the necessary object header for out cfunc_t table. The string
  1144.  * is the ICI name for the function. The last field is the address
  1145.  * of the C function that implements this function.
  1146.  */
  1147. cfunc_t skt_cfuncs[] =
  1148. {
  1149.     {CF_OBJ, "socket",          f_socket},
  1150.     {CF_OBJ, "listen",          f_listen},
  1151.     {CF_OBJ, "accept",          f_accept},
  1152.     {CF_OBJ, "connect",         f_connect},
  1153.     {CF_OBJ, "bind",            f_bind},
  1154.     {CF_OBJ, "select",          f_select},
  1155.     {CF_OBJ, "getsockopt",      f_getsockopt},
  1156.     {CF_OBJ, "setsockopt",      f_setsockopt},
  1157.     {CF_OBJ, "domainname",      f_domainname},
  1158.     {CF_OBJ, "hostname",        f_hostname},
  1159.     {CF_OBJ, "username",        f_username},
  1160.     {CF_OBJ, "getpeername",     f_getpeername},
  1161.     {CF_OBJ, "getsockname",     f_getsockname},
  1162.     {CF_OBJ, "sendto",          f_sendto},
  1163.     {CF_OBJ, "recvfrom",        f_recvfrom},
  1164.     {CF_OBJ, "send",            f_send},
  1165.     {CF_OBJ, "recv",            f_recv},
  1166.     {CF_OBJ, "getportno",       f_getportno},
  1167.     {CF_OBJ, "gethostbyname",   f_gethostbyname},
  1168.     {CF_OBJ, "gethostbyaddr",   f_gethostbyaddr},
  1169.     {CF_OBJ, "sktno",        f_sktno},
  1170.     {CF_OBJ, "sktopen",        f_sktopen},
  1171.     {CF_OBJ}
  1172. };
  1173.  
  1174. #endif /*NOSKT*/
  1175.